package edu.ucla.rendezvous;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;

import edu.ucla.rendezvous.util.PacketParserUtil;

public class RendezvousServerThread extends Thread {

	public static String currentRoot = null;
	public static Timer rootTimer = new Timer();
	
	public static int timerRefreshCount = 0;
	public static int delay = 0;   				// delay before kicking off the timer
	public static int period = 2000;  			// delay between calling .run()

    private static Socket socket = null;
	private static BufferedReader in = null;
	private static PrintWriter out = null;
	
	public RendezvousServerThread(Socket socket) {
    	super("RendezvousServerThread");
    	this.socket = socket;
	}
	
	public class RefreshThread extends TimerTask {
		@Override
		public void run() {
			System.out.println("Checking root, currentRoot="+currentRoot);
			if(timerRefreshCount > 3) {	// We have not gotten a refresh, and the timer has run out
				System.out.println("Dropping current root: " + currentRoot);
				synchronized(this) { 
					currentRoot = null;
				}
				timerRefreshCount = 0;
				this.cancel();
			}
			timerRefreshCount++;
		}
	}
	
	/** 
	 * Creates a timer thread that waits for REFRESH messages from the root node, and if it 
	 * gets them is happy, if not, it removes it as the root. 
	 * 
	 * @param inputLine IP Address of the current root node.
	 */
	private void deployTimer(String inputLine) {
		synchronized(this) { 
			currentRoot = inputLine;
		}
		rootTimer.scheduleAtFixedRate(new RefreshThread(), delay, period);
	}
	
	/**
	 * The RendezvousServer accepts two kinds of packets. Either it's a REFRESH from the
	 * root server or it's a request for a root server from a client that wants to join the group.
	 * 
	 * @param clientSocket
	 * @throws IOException
	 */
	private void processSocket() throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
		
		String inputLine;
		while ((inputLine = in.readLine()) != null) {
			byte[] pkt = inputLine.getBytes();
			
			String packetType = PacketParserUtil.getPacketType(pkt);
			String packetPayload = PacketParserUtil.getPacketPayload(pkt);
			
			if(packetType.equals("REFRESH")) {	
				//if(refreshIP.equals(currentRoot)) {
				timerRefreshCount = 0;			// Obtaining a single REFRESH from the root causes the timer to be refreshed
				//}
			} else if(packetType.equals("HELLO")) {
				if(currentRoot == null) {
					deployTimer(packetPayload);
				}
				byte[] buf = PacketParserUtil.createPacket("HELLO-REPLY", currentRoot);
				out.println(new String(buf));
			} else { 
				// Invalid request
			}
		}
		out.close();
		in.close();
	}

	public void run() {
		try {
			processSocket();
		} catch (IOException e) {
			System.err.println("Accept failed.");
			System.exit(1);
		}
	}
	
}